import java.awt.Component;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.BevelBorder;

/*
 * Map.java
 *
 * $LastChangedDate: 2008-05-29 11:00:51 +0000 (Thu, 29 May 2008) $
 * $LastChangedRevision: 38 $
 * Vicente J. Ferrer Dalmau
 * < vicente@jdalmau.es >
 *
 */

/**
 * Creates a new Map divided in Zones.
 * @author Vicente J. Ferrer Dalmau
 */
public class Map extends JPanel {
    
    public int SIZE;
    public int ZONES;
    public int COLORS;
    public Zone[][] board;
    public Zone[] zones;
    public GridLayout layout;
    public ConstraintsDialog constraints;
    
    /** Creates a new instance of Map
     * @param zones the map will have n=zones squares to get painted
     * @param constraintsDialog the Dialog that will allow defining constraints 
     * over single Zones.
     */
    public Map(int zones, int colors, ConstraintsDialog constraintsDialog) {
        
        System.out.println("Map.Map(): Created new MAP with "+colors+" colors.");
        // we want a squared board
        SIZE = (int)Math.ceil(Math.sqrt((double)zones));
        ZONES = zones;
        COLORS = colors;
        constraints = constraintsDialog;
        board = new Zone[SIZE][SIZE];
        this.zones = new Zone[ZONES];
        int row, column;
        Zone zone;
        
        // sets a GridLayout
        layout = new GridLayout(SIZE, SIZE);
        layout.setHgap(1);
        layout.setVgap(1);
        this.setLayout(layout);
        
        // sets a border
        this.setBorder(new BevelBorder(BevelBorder.RAISED));
        
        // we'll need a random generator
        Random rnd = new Random();                
        
        // init the board
        
        for (int i=0; i<ZONES; i++) {
            
            row = rnd.nextInt(SIZE);
            column = rnd.nextInt(SIZE);
            while (board[row][column] != null) {
                row = rnd.nextInt(SIZE);
                column = rnd.nextInt(SIZE);
            }
             
            // creates a new square
            zone = new Zone(this, row, column, i, "images/forest.jpg", true);
            this.zones[i] = zone;
            board[row][column] = zone;            
        }                 
        
        // now append the Zones to the Map in the JPanel
        for (row=0; row<SIZE; row++)
            for(column=0; column<SIZE; column++) {
                if (board[row][column] == null) {
                    zone = new Zone(this, row, column, -1, "images/water.jpg", false);
                    this.board[row][column] = zone;
                    this.add(zone);
                }
                else
                    this.add(board[row][column]);
            }
        
        // sets the adjacent Zones for each Zone
        for (int i=0; i<ZONES; i++)
            this.zones[i].adjacentZones = getAdjacentZones(this.zones[i]);
        
        /*
        for(int f=0; f<this.SIZE; f++) {
            for(int c=0; c<this.SIZE; c++)
                System.out.print(board[f][c].NUMBER+", ");
            System.out.println("");
        }
        */
    }
    
    /** Shows the Constraints Dialog to apply some constraints to zone 
     * @param zone the Zone that has been clicked.
     */
    public void showConstraintsDialog (Zone zone) {
        
        if (constraints != null)
            constraints.show(zone);
    }
    
    /** Gets the adjacent Zones of a given Zone.
     */
    public ArrayList getAdjacentZones (Zone zone) {
        
        ArrayList list = new ArrayList();        
        
        // north
        if (zone.ROW != 0)
            if ((this.board[zone.ROW-1][zone.COLUMN]).NUMBER != -1)
                list.add((Object)(this.board[zone.ROW-1][zone.COLUMN]));
        
        // east
        if (zone.COLUMN != this.SIZE-1)
            if ((this.board[zone.ROW][zone.COLUMN+1]).NUMBER != -1)
                list.add((Object)(this.board[zone.ROW][zone.COLUMN+1]));
        
        // south
        if (zone.ROW != this.SIZE-1)
            if ((this.board[zone.ROW+1][zone.COLUMN]).NUMBER != -1)
                list.add((Object)(this.board[zone.ROW+1][zone.COLUMN]));
        
        // west
        if (zone.COLUMN != 0)
            if ((this.board[zone.ROW][zone.COLUMN-1]).NUMBER != -1)
                list.add((Object)(this.board[zone.ROW][zone.COLUMN-1]));
        
        return list;
    }
    
    /** Updates de GUI 
     */
    public void refresh () {
        
        this.revalidate();
        this.repaint();        
    }
   
    /** Clears the map
     */
    public void clear () {
        
        for (int i=0; i<this.ZONES; i++)
            this.zones[i].clear();
    }
    
    private void orderColorsArrayList (ArrayList colors) {                
        
        int lower;
        for (int i=0; i<colors.size(); i++) {
            lower = i;
            for (int j=i+1; j<colors.size(); j++) {
                if (((MyColor)colors.get(j)).position < ((MyColor)colors.get(lower)).position)
                    lower = j;
            }
            // swap
            if (lower != i) {
                Object aux = colors.get(i);
                colors.set(i, colors.get(lower));
                colors.set(lower, aux);
            }
        }              
    }
    
    /** Adds radom constraints to the map
     */
    public void addRandomConstraints() {
        
        clear();
        // we'll need a random generator
        Random rnd = new Random();
        for (int i=0; i<this.ZONES; i++) {
            if (rnd.nextBoolean()) {
                int quantity = rnd.nextInt(this.COLORS);
                if (quantity != 0) {
                    ArrayList colorsArray = new ArrayList();
                    while (quantity > 0) {
                        int color = rnd.nextInt(this.COLORS);
                        while (colorsArray.contains(ColorsList.mycolors[color])) {
                            color = rnd.nextInt(this.COLORS);
                        }
                        colorsArray.add(ColorsList.mycolors[color]);
                        quantity--;
                    }
                    //order the colors array
                    orderColorsArrayList(colorsArray);

                    zones[i].addConstraints(colorsArray.toArray());
                }
            }
        }
        refresh();
    }    
}
